package gestordeentidades.gateways;

import entidades.Cor;
import gestordeentidades.identitymap.interfaces.IEntityMap;
import gestordeentidades.persistance.database.Converter;
import gestordeentidades.persistance.interfaces.IDataBaseAdapter;
import gestordeentidades.persistance.interfaces.IDataBaseRow;
import gestordeentidades.persistance.interfaces.IDataBaseStatement;
import gestordeentidades.persistance.interfaces.IGateway;
import gestordeentidades.persistance.interfaces.ILinha;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import entidades.Decorador;
import entidades.Telha;
import entidades.Textura;
import entidades.interfaces.ITelhaBaseVisitante;
import gestordeentidades.persistance.DataBaseObject;
import gestordeentidades.persistance.database.SQLtype;

/**
 * Trabalho DAS - 2014/2015
 * @author a21210380, a21190325, a21210392
 */
public class DecoradorGateway implements IGateway<Decorador> {

    private static final Logger logger = Logger.getLogger(DecoradorGateway.class.getName());

    public static final String SQL_CREATE = "CREATE TABLE IF NOT EXISTS decorador ("
            + "id " + Converter.convertToSqlText(int.class) + " NOT NULL,"
            + "id_telha " + Converter.convertToSqlText(int.class) + " NOT NULL,"
            + "id_textura " + Converter.convertToSqlText(int.class) + ","
            + "id_cor_linha " + Converter.convertToSqlText(int.class) + ","
            + "id_cor_texto " + Converter.convertToSqlText(int.class) + ","
            + "nome " + Converter.convertToSqlText(String.class) + " NOT NULL,"
            + "decorador " + Converter.convertToSqlText(boolean.class) + " NOT NULL);";
    public static final String SQL_DROP = "DROP TABLE decorador;";
    public static final String SQL_INSERT = "INSERT INTO decorador VALUES (?,?,?,?,?,?,?);";
    public static final String SQL_UPDATE = "UPDATE decorador SET id_telha=?,id_textura=?,id_cor_linha=?,id_cor_texto=?,nome=?, decorador=? WHERE id=?;";
    public static final String SQL_DELETE = "DELETE FROM decorador WHERE id=?;";
    public static final String SQL_FIND_BY_ID = "SELECT * FROM decorador WHERE id=?;";
    public static final String SQL_FIND_ALL = "SELECT * FROM decorador;";
    
    @Override
    public void initTable(IDataBaseAdapter dataBase) {
        dataBase.executarSql(SQL_CREATE);
    }

    @Override
    public void dropTable(IDataBaseAdapter dataBase) {
        dataBase.executarSql(SQL_DROP);
    }

    @Override
    public boolean inserirNovaEntidade(IDataBaseAdapter dataBase, Decorador object) {
        IDataBaseStatement statement = dataBase.getDataBaseStatement(SQL_INSERT);
        statement.adicionarParametroSql(1, object.getId(), Converter.convertToSqlText(int.class));
        statement.adicionarParametroSql(2, object.getTelhaDecorada().getId(), Converter.convertToSqlText(int.class));
        
        HashMap<Integer, DataBaseObject> valores = object.getValores();
        if(valores.containsKey(Decorador.VALOR_FUNDO)) {
            statement.adicionarParametroSql(3, valores.get(Decorador.VALOR_FUNDO).getId(), Converter.convertToSqlText(int.class));
        } else {
            statement.adicionarParametroSql(3, null, SQLtype.NULL);
        }
        
        if(valores.containsKey(Decorador.VALOR_COR_LINHA)) {
            statement.adicionarParametroSql(4, valores.get(Decorador.VALOR_COR_LINHA).getId(), Converter.convertToSqlText(int.class));
        } else {
            statement.adicionarParametroSql(4, null, SQLtype.NULL);
        }
        
        if(valores.containsKey(Decorador.VALOR_COR_TEXTO)) {
            statement.adicionarParametroSql(5, valores.get(Decorador.VALOR_COR_TEXTO).getId(), Converter.convertToSqlText(int.class));
        } else {
            statement.adicionarParametroSql(5, null, SQLtype.NULL);
        }
        
        statement.adicionarParametroSql(6, object.getNomeDecorador(), Converter.convertToSqlText(String.class));
        
        object.getTelhaDecorada().accept(new ITelhaBaseVisitante() {

            @Override
            public void visitante(Telha telha) {
                statement.adicionarParametroSql(7, false, Converter.convertToSqlText(boolean.class));
            }

            @Override
            public void visitante(Decorador decorador) {
                statement.adicionarParametroSql(7, true, Converter.convertToSqlText(boolean.class));
            }
        });
        
        return (dataBase.inserir(statement) == 1);
    }

    @Override
    public boolean atualizarEntidade(IDataBaseAdapter dataBase, Decorador object) {
        IDataBaseStatement statement = dataBase.getDataBaseStatement(SQL_UPDATE);
        statement.adicionarParametroSql(1, object.getTelhaDecorada().getId(), Converter.convertToSqlText(int.class));
        
        HashMap<Integer, DataBaseObject> valores = object.getValores();
        if(valores.containsKey(Decorador.VALOR_FUNDO)) {
            statement.adicionarParametroSql(2, valores.get(Decorador.VALOR_FUNDO).getId(), Converter.convertToSqlText(int.class));
        } else {
            statement.adicionarParametroSql(3, null, SQLtype.NULL);
        }
        
        if(valores.containsKey(Decorador.VALOR_COR_LINHA)) {
            statement.adicionarParametroSql(3, valores.get(Decorador.VALOR_COR_LINHA).getId(), Converter.convertToSqlText(int.class));
        } else {
            statement.adicionarParametroSql(3, null, SQLtype.NULL);
        }
        
        if(valores.containsKey(Decorador.VALOR_COR_TEXTO)) {
            statement.adicionarParametroSql(4, valores.get(Decorador.VALOR_COR_TEXTO).getId(), Converter.convertToSqlText(int.class));
        } else {
            statement.adicionarParametroSql(4, null, SQLtype.NULL);
        }
        
        statement.adicionarParametroSql(5, object.getNomeDecorador(), Converter.convertToSqlText(String.class));
        
        
        object.getTelhaDecorada().accept(new ITelhaBaseVisitante() {

            @Override
            public void visitante(Telha telha) {
                statement.adicionarParametroSql(6, false, Converter.convertToSqlText(boolean.class));
            }

            @Override
            public void visitante(Decorador decorador) {
                statement.adicionarParametroSql(6, true, Converter.convertToSqlText(boolean.class));
            }
        });
        
        statement.adicionarParametroSql(7, object.getId(), Converter.convertToSqlText(int.class));
        return (dataBase.atualizar(statement) == 1);
    }

    @Override
    public boolean apagarEntidade(IDataBaseAdapter dataBase, Decorador object) {
        IDataBaseStatement statement = dataBase.getDataBaseStatement(SQL_DELETE);
        statement.adicionarParametroSql(1, object.getId(), Converter.convertToSqlText(int.class));
        return (dataBase.atualizar(statement) == 1);
    }

    @Override
    public Decorador procurarEntidadePeloID(IDataBaseAdapter dataBase, IEntityMap entityMap, int id) {
        IDataBaseStatement statement = dataBase.getDataBaseStatement(SQL_FIND_BY_ID);
        statement.adicionarParametroSql(1, id, Converter.convertToSqlText(int.class));
        ProcurarPorID d = new ProcurarPorID(entityMap);
        dataBase.ler(statement, d);
        return d.getDecorador();
    }

    @Override
    public Map<Integer, Decorador> procurarPorTodasAsEntidadesComoMapa(IDataBaseAdapter dataBase, IEntityMap entityMap) {
        IDataBaseStatement statement = dataBase.getDataBaseStatement(SQL_FIND_ALL);
        ProcurarComoMapa d = new ProcurarComoMapa(entityMap);
        dataBase.ler(statement, d);
        return d.getDecoradores();
    }
    
    private class ProcurarPorID implements IDataBaseRow {
        private final IEntityMap entityMap;
        private Decorador decorador = null;

        ProcurarPorID(IEntityMap entityMap) {
            this.entityMap = entityMap;
        }
        
        public Decorador getDecorador() {
            return decorador;
        }

        @Override
        public void onLinhaLida(ILinha linha) {
            int id = linha.getInt("id");
            Integer id_textura = linha.getInteger("id_textura");
            Integer id_cor_linha = linha.getInteger("id_cor_linha");
            Integer id_cor_texto = linha.getInteger("id_cor_texto");
            boolean isDecorador = linha.getBoolean("decorador");
            String nome = linha.getString("nome");
            int id_telha = linha.getInt("id_telha");
            
            Decorador d;
            
            if(isDecorador) {
                d = new Decorador(
                        nome,
                        entityMap.procurarEntidadePeloID(Decorador.class, id_telha),
                        (id_cor_linha == null ? null : entityMap.procurarEntidadePeloID(Cor.class, id_cor_linha)),
                        (id_cor_texto == null ? null : entityMap.procurarEntidadePeloID(Cor.class, id_cor_texto)),
                        (id_textura == null ? null : entityMap.procurarEntidadePeloID(Textura.class, id_telha)));
            } else {
                d = new Decorador(
                        nome,
                        entityMap.procurarEntidadePeloID(Telha.class, id_telha),
                        (id_cor_linha == null ? null : entityMap.procurarEntidadePeloID(Cor.class, id_cor_linha)),
                        (id_cor_texto == null ? null : entityMap.procurarEntidadePeloID(Cor.class, id_cor_texto)),
                        (id_textura == null ? null : entityMap.procurarEntidadePeloID(Textura.class, id_telha)));
            }
            
            Field idField;
            try {
                idField = d.getClass().getSuperclass().getSuperclass().getDeclaredField("id");
                idField.setAccessible(true);

                idField.setInt(d, id);
                decorador = d;
            } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
                logger.logp(Level.SEVERE, DecoradorGateway.class.getName(), "ProcurarPorID-onLinhaLida()", "Reflection API!", ex);
            }
        }
    }
    
    private class ProcurarComoMapa implements IDataBaseRow {
        private final IEntityMap entityMap;
        private final Map<Integer, Decorador> mapa = new HashMap<>();

        ProcurarComoMapa(IEntityMap entityMap) {
            this.entityMap = entityMap;
        }
        
        public Map<Integer, Decorador> getDecoradores() {
            return mapa;
        }

        @Override
        public void onLinhaLida(ILinha linha) {
            int id = linha.getInt("id");
            Integer id_textura = linha.getInteger("id_textura");
            Integer id_cor_linha = linha.getInteger("id_cor_linha");
            Integer id_cor_texto = linha.getInteger("id_cor_texto");
            boolean isDecorador = linha.getBoolean("decorador");
            String nome = linha.getString("nome");
            int id_telha = linha.getInt("id_telha");
            
            Decorador d;
            
            if(isDecorador) {
                d = new Decorador(
                        nome,
                        entityMap.procurarEntidadePeloID(Decorador.class, id_telha),
                        (id_cor_linha == null ? null : entityMap.procurarEntidadePeloID(Cor.class, id_cor_linha)),
                        (id_cor_texto == null ? null : entityMap.procurarEntidadePeloID(Cor.class, id_cor_texto)),
                        (id_textura == null ? null : entityMap.procurarEntidadePeloID(Textura.class, id_telha)));
            } else {
                d = new Decorador(
                        nome,
                        entityMap.procurarEntidadePeloID(Telha.class, id_telha),
                        (id_cor_linha == null ? null : entityMap.procurarEntidadePeloID(Cor.class, id_cor_linha)),
                        (id_cor_texto == null ? null : entityMap.procurarEntidadePeloID(Cor.class, id_cor_texto)),
                        (id_textura == null ? null : entityMap.procurarEntidadePeloID(Textura.class, id_telha)));
            }
            
            Field idField;
            try {
                idField = d.getClass().getSuperclass().getSuperclass().getDeclaredField("id");
                idField.setAccessible(true);

                idField.setInt(d, id);
                mapa.put(id, d);
            } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
                logger.logp(Level.SEVERE, DecoradorGateway.class.getName(), "ProcurarComoMapa-onLinhaLida()", "Reflection API!", ex);
            }
        }
    }
}
